package com.enzoism.springboot.dive.bis.iterator;

import java.util.*;
import java.util.function.Consumer;

/**
 * 【原生】通过伪代码理解迭代器的核心内容
 * @param <E>
 */
public class MyArrayList<E> {
    // 内部的elementData的操作次数(因为没有加锁，用这个来判断是否有其他线程修改了当前对象)
    int modCount;
    // 数组的size
    int size;
    // 内部维护的数组
    Object[] elementData;
    // 对象移除方法
    public E remove(int index) {
        modCount++;
        E oldValue = (E)elementData[index];

        // 移除对象后，将后续的数据进行移动
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                    numMoved);
        // 将数据置空，让后续GC进行对象清理
        elementData[--size] = null; // clear to let GC do its work
        return oldValue;
    }
    //-----------------迭代器-----------------//
    /**
     *     ArrayList默认的迭代器就是Itr，可以进行对象移除
     *     1）添加-使用ListIterator进行添加
     *     2）删除-使用Iterator进行移除
     *     public Iterator<E> iterator() {
     *         return new Itr();
     *     }
     */
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = MyArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                MyArrayList.this.remove(lastRet);
                cursor = lastRet;
                // 移除之后，重置条件，需要想再次remove，就必须再调用一次next方法
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = MyArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = MyArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

}